﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Is.Test
{
    internal class ComplexObject
    {
        public ComplexObject Object { get; private set; }

        public int Value { get; private set; }

        public bool? BoolValue { get; private set; }

        public ComplexObject FieldObject;

        public int FieldValue;
        public bool? BoolFieldValue;

        public ComplexObject GetObject()
        {
            return Object;
        }

        public int GetValue()
        {
            return Value;
        }

        public bool? GetBoolValue()
        {
            return BoolValue;
        }

        public ComplexObject(ComplexObject complexObject, int value)
            : this(complexObject, value, null)
        {
        }

        public ComplexObject(ComplexObject complexObject, int value, bool? boolValue)
        {
            Object = complexObject;
            Value = value;
            BoolValue = boolValue;

            FieldObject = complexObject;
            FieldValue = value;
            BoolFieldValue = boolValue;
        }
    }

    internal class ComparableObject : IComparable
    {
        public int Value { get; private set; }

        public ComparableObject(int value)
        {
            Value = value;
        }

        public int CompareTo(object obj)
        {
            return Value.CompareTo(((ComparableObject)obj).Value);
        }
    }

    internal class DerivedComparableObject : ComparableObject
    {
        public DerivedComparableObject(int value) : base(value) { }
    }

    internal class GenericComparableObject : IComparable<GenericComparableObject>
    {
        public int Value { get; private set; }

        public GenericComparableObject(int value)
        {
            Value = value;
        }

        public int CompareTo(GenericComparableObject other)
        {
            return Value.CompareTo(other.Value);
        }
    }

    internal class DerivedGenericComparableObject : GenericComparableObject
    {
        public DerivedGenericComparableObject(int value) : base(value) { }
    }

    internal class IntGenerator
    {
        public static IEnumerable<int> Range(int start, int end)
        {
            for (int i = start; i <= end; i++)
                yield return i;
        }
    }

    internal class EquatableObject : IEquatable<EquatableObject>
    {
        public bool Equals__Called;
        public EquatableObject Equals_Other;
        public readonly int Value;

        public EquatableObject(int value)
        {
            Value = value;
        }

        public bool Equals(EquatableObject other)
        {
            Equals__Called = true;
            Equals_Other = other;
            if (other == null) return false;
            return Value.Equals(other.Value);
        }
    }

    internal abstract class CustomEqualityObject
    {
        public bool EqualsCalled;
        public object EqualsCalledOn;
        public readonly int Value;

        public CustomEqualityObject(int value)
        {
            Value = value;
        }

        public override bool Equals(object obj)
        {
            EqualsCalled = true;
            EqualsCalledOn = obj;
            if (obj == null) return false;
            if (obj.GetType() != this.GetType()) return false;
            return Equals((CustomEqualityObject)obj);
        }

        public bool Equals(CustomEqualityObject obj)
        {
            if (obj == null) return false;
            EqualsCalled = true;
            EqualsCalledOn = obj;
            return Value.Equals(obj.Value);
        }

        public override int GetHashCode()
        {
            return Value.GetHashCode();
        }
    }

    internal class DerivedCustomEqualityObject : CustomEqualityObject
    {
        public readonly int ValueInDerived;

        public DerivedCustomEqualityObject(int value, int valueInDerived) : base(value)
        {
            ValueInDerived = valueInDerived;
        }
    }

    internal class DerivedCustomEqualityObjectB : CustomEqualityObject
    {
        public readonly int ValueInDerived;

        public DerivedCustomEqualityObjectB(int value, int valueInDerived)
            : base(value)
        {
            ValueInDerived = valueInDerived;
        }
    }

    internal class DerivedCustomEqualityObjectWithOwnEquality : CustomEqualityObject
    {
        public readonly int ValueInDerived;

        public DerivedCustomEqualityObjectWithOwnEquality(int value, int valueInDerived)
            : base(value)
        {
            ValueInDerived = valueInDerived;
        }

        public override bool Equals(object obj)
        {
            EqualsCalled = true;
            EqualsCalledOn = obj;
            if (obj == null) return false;
            if (obj.GetType() != this.GetType()) return false;
            return Equals((DerivedCustomEqualityObjectWithOwnEquality)obj);
        }

        public bool Equals(DerivedCustomEqualityObjectWithOwnEquality obj)
        {
            if (obj == null) return false;
            EqualsCalled = true;
            EqualsCalledOn = obj;
            return Value.Equals(obj.Value) && ValueInDerived.Equals(obj.ValueInDerived);
        }

        public override int GetHashCode()
        {
            int result = Value.GetHashCode();
            result = (result*397) ^ ValueInDerived.GetHashCode();
            return result;
        }
    }

    internal class DerivedCustomEqualityObjectWithOwnEqualityB : CustomEqualityObject
    {
        public readonly int ValueInDerived;

        public DerivedCustomEqualityObjectWithOwnEqualityB(int value, int valueInDerived)
            : base(value)
        {
            ValueInDerived = valueInDerived;
        }

        public override bool Equals(object obj)
        {
            EqualsCalled = true;
            EqualsCalledOn = obj;
            if (obj == null) return false;
            if (obj.GetType() != this.GetType()) return false;
            return Equals((DerivedCustomEqualityObjectWithOwnEqualityB)obj);
        }

        public bool Equals(DerivedCustomEqualityObjectWithOwnEqualityB obj)
        {
            if (obj == null) return false;
            EqualsCalled = true;
            EqualsCalledOn = obj;
            return Value.Equals(obj.Value) && ValueInDerived.Equals(obj.ValueInDerived);
        }

        public override int GetHashCode()
        {
            int result = Value.GetHashCode();
            result = (result * 397) ^ ValueInDerived.GetHashCode();
            return result;
        }
    }

    internal class DefaultEqualityObject
    {
    }

    internal class DerivedDefaultEqualityObject : DefaultEqualityObject
    {
    }

    internal class DerivedEquatableObject : EquatableObject
    {
        public readonly int ValueInDerived;

        public DerivedEquatableObject(int value, int valueInDerived) : base(value)
        {
            ValueInDerived = valueInDerived;
        }
    }

    internal enum TestEnum
    {
        Alma,
        Szilva
    }
}
